package GivenInstances

import scala.util.{Success, Try}

trait StringParser[A]:
  def parse(s: String): Try[A]

object StringParser:
  def apply[A](using parser: StringParser[A]): StringParser[A] = parser

  private def baseParser[A](f: String => Try[A]): StringParser[A] = new StringParser[A] {
    override def parse(s: String): Try[A] = f(s)
  }


  given stringParser: StringParser[String] = baseParser(Success(_))
  given intParser: StringParser[Int] = baseParser(s => Try(s.toInt))

  given optionParser[A](using parser: => StringParser[A]): StringParser[Option[A]] = new StringParser[Option[A]] {
    override def parse(s: String) = s match {
      case "" => Success(None)
      case str => parser.parse(str).map(x => Some(x))
    }
  }

def test: Unit =
  val parser = summon[StringParser[Option[Int]]]

  println(parser.parse("21"))
  println(parser.parse(""))
  println(parser.parse("21a"))
  println(summon[StringParser[Option[Int]]](using StringParser.optionParser[Int]).parse("42"))